package com.putao.tinytime.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.RectF;
import android.graphics.Region;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.view.MotionEvent;
import android.view.View;

import com.putao.camera.collage.JNIFUN;
import com.putao.tinytime.util.Loger;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by jidongdong on 15/1/28.
 */
public class SceneSynthesisView extends View {
    private List<CollagePhotoSet> mPhotoList;
    private float down_x, down_y;
    private int touchIndex = -1;
    private int touchIndex2 = -1;
    private Paint mPaint = new Paint();
    private int mViewWidth = Integer.MAX_VALUE;
    private int mViewHeight = Integer.MAX_VALUE;
    PointF mid = new PointF();
    private int currentMode = OperateMode.NONE;
    float oldDistacne = 1.0f;
    float zoomRate = 1.0f;
    private Matrix currentMatrix = new Matrix();
    private OnPhotoAreaClickListener mOnPhotoAreaClickListener;
    private OnPhotoAreaSelectedListener mOnPhotoAreaSelectedListener;
    private boolean isMoved = false;
    private boolean isZoomed = false;

    public SceneSynthesisView(Context context) {
        super(context);
        init(context);
    }

    public SceneSynthesisView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public SceneSynthesisView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    /**
     * 计算两点之间的距离
     *
     * @param event
     * @return
     */
    private float spacing(MotionEvent event) {
        float x = event.getX(0) - event.getX(1);
        float y = event.getY(0) - event.getY(1);
        return FloatMath.sqrt(x * x + y * y);
    }

    /**
     * 计算两个点的中点坐标
     *
     * @param point
     * @param event
     */
    private void midPoint(PointF point, MotionEvent event) {
        float x = event.getX(0) + event.getX(1);
        float y = event.getY(0) + event.getY(1);
        point.set(x / 2, y / 2);
    }

    private void init(Context context) {
        mPaint.setAntiAlias(true);
        this.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mOnPhotoAreaClickListener != null)
                    mOnPhotoAreaClickListener.clicked(touchIndex);
            }
        });
    }

    public void setOnPhotoAreaClickListener(OnPhotoAreaClickListener listener) {
        mOnPhotoAreaClickListener = listener;
    }

    public void setOnPhotoAreaSelectedListener(OnPhotoAreaSelectedListener listener) {
        mOnPhotoAreaSelectedListener = listener;
    }

    public static interface OnPhotoAreaClickListener {
        void clicked(int index);
    }

    public static interface OnPhotoAreaSelectedListener {
        void selectedChanged(int index);

    }


    /**
     * 设置模板照片列表
     *
     * @param photolist
     */
    public void setImageList(ArrayList<CollagePhotoSet> photolist) {
        mPhotoList = photolist;
        invalidate();
    }

    public void changePhoto(Bitmap photo, int index) {
        if (index > -1 && mPhotoList.size() > 0) {
            mViewWidth = getWidth();
            mViewHeight = getHeight();
            mPhotoList.get(index).resetPhoto(photo);
            invalidate();
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int width;
        int height;
        if (widthMode == MeasureSpec.EXACTLY) {
            width = widthSize;
        } else {
            width = (mViewWidth != Integer.MAX_VALUE) ? mViewWidth : widthSize;
        }
        if (heightMode == MeasureSpec.EXACTLY) {
            height = heightSize;
        } else {
            height = (mViewHeight != Integer.MAX_VALUE) ? mViewHeight
                    : heightSize;
        }
        setMeasuredDimension(width, height);
    }

    /**
     * 小到大的排序
     *
     * @param targetArr
     */
    public void sort(float[] targetArr) {
        float temp;
        for (int i = 0; i < targetArr.length; i++) {
            for (int j = i; j < targetArr.length; j++) {
                if (targetArr[i] > targetArr[j]) {
                    temp = targetArr[i];
                    targetArr[i] = targetArr[j];
                    targetArr[j] = temp;
                }
            }
        }
    }

    private Bitmap clipPolygonBitmap(CollagePhotoSet photo, int width,
                                     int height, int index) {
        Bitmap bit = clipPolygonBitmap(photo.Photo, photo.Points, photo.matrix,
                width, height);
        if (mPhotoList.get(index).ClipPhoto != null) {
            mPhotoList.get(index).ClipPhoto.recycle();
        }
        mPhotoList.get(index).ClipPhoto = bit;
        return bit;
    }

    private Bitmap clipPolygonBitmap(Bitmap bitmap, Area area, Matrix matrix,
                                     int width, int height) {
        Bitmap bit = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);

        Paint paint = new Paint();
        paint.setAntiAlias(true);
        Canvas canvas = new Canvas(bit);
        canvas.drawARGB(0, 0, 0, 0);
        Path path = new Path();
        path.reset();
        path.moveTo(area.PloyX[0], area.PloyY[0]);
        for (int i = 1; i < area.PloyX.length; i++) {
            path.lineTo(area.PloyX[i], area.PloyY[i]);
        }
        path.close();
        canvas.clipPath(path, Region.Op.INTERSECT);
//        if (touchIndex > -1) {
//            matrix = dealImageMatrixLimit();
//        }
        canvas.drawBitmap(bitmap, matrix, paint);
        return bit;
    }

    private Matrix dealImageMatrixLimit() {
        CollagePhotoSet photo = mPhotoList.get(touchIndex);
        // 图片显示区域
        RectF showRect = photo.ShowRect;
        Matrix matrix = new Matrix();
        matrix.set(photo.matrix);
        int realwidth = photo.Photo.getWidth();
        int realheight = photo.Photo.getHeight();
        RectF rect = new RectF(0, 0, realwidth, realheight);
        matrix.mapRect(rect);
        float currentwidth = rect.width();
        float currentheight = rect.height();
        float scale = 1f;
        if (currentwidth < showRect.width() || currentheight < showRect.height()) {
            float image_ratio = currentwidth / currentheight;
            float show_ratio = showRect.width() / showRect.height();
            if (show_ratio > image_ratio) {
                scale = showRect.width() / currentwidth;
            } else {
                scale = showRect.height() / currentheight;
            }
        }
        float transX = 0;
        float transY = 0;
        if (currentwidth > showRect.width() && currentheight > showRect.height()) {//图片大于显示区域

            if (rect.left > showRect.left) {
                transX = showRect.left - rect.left;
            }
            if (rect.right < showRect.right) {
                transX = showRect.right - rect.right;
            }
            if (rect.top > showRect.top) {
                transY = showRect.top - rect.top;
            }
            if (rect.bottom < showRect.bottom) {
                transY = showRect.bottom - rect.bottom;
            }


        } else//图片小于显示区域
        {
            transX = showRect.left - rect.left;
            transY = showRect.top - rect.top;
        }
        matrix.postTranslate(transX, transY);
        matrix.postScale(scale, scale, showRect.left, showRect.top);
        mPhotoList.get(touchIndex).matrix.set(matrix);
        return matrix;
    }

    private void drawCollagePath(Canvas canvas, Path path) {
        Paint borderpaint = new Paint();
        borderpaint.setStyle(Paint.Style.STROKE);
        borderpaint.setAntiAlias(true);
        borderpaint.setColor(Color.RED);
        borderpaint.setStrokeWidth(2);
        canvas.drawPath(path, borderpaint);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawARGB(0, 0, 0, 0);
        try {
            canvas.save();
            for (int j = 0; j < mPhotoList.size(); j++) {
                CollagePhotoSet set = mPhotoList.get(j);
                Bitmap bitmap = set.ClipPhoto;
                if (touchIndex == j) {
                    bitmap = clipPolygonBitmap(set, mViewWidth, mViewHeight, j);
                }
                canvas.drawBitmap(set.Background, set.Left, set.Top, mPaint);
                canvas.drawBitmap(bitmap, 0, 0, mPaint);
                canvas.drawBitmap(set.Foreground, set.Left, set.Top, mPaint);
            }
            canvas.restore();
//            DrawRectBorder(canvas);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                currentMode = OperateMode.DRAG;
                isMoved = false;
                isZoomed = false;
                down_x = event.getX();
                down_y = event.getY();
                touchIndex = getTouchAreaIndex(down_x, down_y);
                Loger.d("touchIndex--->" + touchIndex);
                if (touchIndex > -1) {
                    currentMatrix.set(mPhotoList.get(touchIndex).matrix);
                }
                if (mOnPhotoAreaSelectedListener != null) {
                    mOnPhotoAreaSelectedListener.selectedChanged(touchIndex);
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (currentMode == OperateMode.DRAG) {
                    float move_x = event.getX() - down_x;
                    float move_y = event.getY() - down_y;
                    float move_distance = FloatMath.sqrt(move_x * move_x + move_y
                            * move_y);
                    if (touchIndex > -1 && move_distance > 5f) {
                        isMoved = true;
                        down_x = event.getX();
                        down_y = event.getY();
                        currentMatrix.postTranslate(move_x, move_y);
                        mPhotoList.get(touchIndex).matrix.set(currentMatrix);
                        invalidate();
                    }
                } else if (currentMode == OperateMode.ZOOM) {
                    float newDistance = spacing(event);
                    zoomRate = newDistance / oldDistacne;
                    if ((touchIndex == touchIndex2) && (touchIndex > -1)) {
                        isZoomed = true;
                        oldDistacne = newDistance;
                        currentMatrix.postScale(zoomRate, zoomRate, mid.x, mid.y);
                        mPhotoList.get(touchIndex).matrix.set(currentMatrix);
                        invalidate();
                    }
                }
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                currentMode = OperateMode.ZOOM;
                touchIndex2 = getTouchAreaIndex(event.getX(1), event.getY(1));
                oldDistacne = spacing(event);
                if ((touchIndex == touchIndex2) && (touchIndex > -1)) {
                    mPhotoList.get(touchIndex).matrix.set(currentMatrix);
                    midPoint(mid, event);
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_POINTER_UP:
                if (touchIndex > -1 && !isZoomed && !isMoved)
                    performClick();
                if (mOnPhotoAreaSelectedListener != null) {
                    mOnPhotoAreaSelectedListener.selectedChanged(-1);
                }
                currentMode = OperateMode.NONE;
                break;
            default:
                break;
        }
        return true;
    }

    void DrawRectBorder(Canvas canvas) {
        Paint paint = new Paint();
        paint.setStyle(Paint.Style.STROKE);
        paint.setAntiAlias(true);
        paint.setColor(Color.RED);
        paint.setStrokeWidth(2);
        for (int i = 0; i < mPhotoList.size(); i++) {
            canvas.drawRect(mPhotoList.get(i).ShowRect, paint);
        }
    }

    private int getTouchAreaIndex(float x, float y) {
        int index = -1;
        for (int i = mPhotoList.size() - 1; i > -1; i--) {
            Area points = mPhotoList.get(i).Points;
            int r = JNIFUN.pointInPolygon(points.PloyX.length, points.PloyX,
                    points.PloyY, x, y);
            if (r > 0) {
                index = i;
                break;
            }
        }
        return index;
    }

    public float[] getScalePloyX(float[] ployx, float scale) {
        float[] new_ployX = new float[ployx.length];
        StringBuilder new_y = new StringBuilder();
        for (int i = 0; i < ployx.length; i++) {
            new_ployX[i] = ployx[i] * scale;
            new_y.append(new_ployX[i] + ",");
        }
        return new_ployX;
    }

    public float[] getScalePloyY(float[] ployy, float scale) {
        float[] new_ployY = new float[ployy.length];
        StringBuilder new_y = new StringBuilder();
        for (int i = 0; i < ployy.length; i++) {
            new_ployY[i] = ployy[i] * scale;
            new_y.append(new_ployY[i] + ",");
        }
        return new_ployY;
    }

    private class OperateMode {
        private static final int NONE = 0;
        private static final int DRAG = 1;
        private static final int ZOOM = 2;
    }


    /**
     * 模板源图片
     */
    public class CollagePhotoSet {
        public float Left;
        public float Top;
        public Bitmap Background;
        public Bitmap Foreground;
        public Bitmap Photo;
        public Bitmap ClipPhoto;
        public Matrix matrix = new Matrix();
        // 显示区域坐标点
        public Area Points;

        public RectF ShowRect = null;

        public CollagePhotoSet(Bitmap photo, Bitmap background, Bitmap foreground, float left, float top, Area points) {
            Left = left;
            Top = top;
            Photo = photo;
            Points = points;
            Background = background;
            Foreground = foreground;
            initshowRect();
            setClipPhoto();
        }

        public void resetPhoto(Bitmap photo) {
            Photo = photo;
            setClipPhoto();
        }

        void setClipPhoto() {
            Loger.d("view size--->" + mViewWidth + "," + mViewHeight);
            ClipPhoto = clipPolygonBitmap(Photo, Points, matrix, mViewWidth,
                    mViewHeight);
        }

        // 计算图片显示区域
        void initshowRect() {
            float[] area_x = Points.PloyX.clone();
            float[] area_y = Points.PloyY.clone();
            sort(area_x);
            sort(area_y);
            ShowRect = new RectF(area_x[0], area_y[0],
                    area_x[area_x.length - 1], area_y[area_y.length - 1]);
        }

    }

    /**
     * 表示一张拼图上的单个显示图片区的坐标点（顺时针）
     */
    public class Area {
        public float[] PloyX;
        public float[] PloyY;

        public Area(float[] ployX, float[] ployY) {
            PloyX = ployX;
            PloyY = ployY;
        }
    }
}
